package com.settlement.system.controller;

import com.settlement.system.common.exception.ServiceException;
import com.settlement.system.funciton.Function;
import com.settlement.system.model.entity.common.TblReceiveRefundShop;
import com.settlement.system.model.entity.common.TblRrOtherCapitalDetail;
import com.settlement.system.service.*;
import com.settlement.system.common.util.common.FasUtil;
import org.springframework.util.CollectionUtils;
import com.alibaba.excel.util.DateUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 收退款-其他货币资金日记账 前端控制器
 *
 * @author Ximi
 * @since 2020-07-13
 */

@Api(tags = "收退款-其他货币资金日记账", description = "收退款-其他货币资金日记账")
@RestController
@RequestMapping("/rr/other_capital/detail")
@Slf4j
public class TblRrOtherCapitalDetailController extends MergeApiExcelController<TblRrOtherCapitalDetail, Map<String, Object>> {

    @Value("${file.download.url}")
    private String fileDownloadUrl;

    @Value("${system.export-root.path}")
    private String exportRootPath;

    @Resource
    private ITblRrOtherCapitalDetailService tblRrOtherCapitalDetailService;

    @Resource
    private ITblReceiveRefundAccountService tblReceiveRefundAccountService;

    @Resource
    private OtherCapitalDetailRefreshService otherCapitalDetailRefreshService;

    @Resource
    private ITblReceiveRefundShopService tblReceiveRefundShopService;

    @Override
    public IBaseService init() {
        return tblRrOtherCapitalDetailService;
    }

    @Override
    public Class<?> getModelClass() {
        return TblRrOtherCapitalDetail.class;
    }

    @Override
    protected void setParamsModel(Map<String, Object> model) {
        FasUtil.formatInQueryCondition(model,"ncVirtualAccountName","ncVirtualAccount",
                "channelNo","ncEnterAccountBody","balanceType",
                "shopNo","shopAccount"
        );
        super.setParamsModel(model);
    }


    /**
     * 验证月份格式
     *
     * @param month
     * @return
     */
    private String verifyMonthFormat(String month) {
        try {
            DateUtils.parseDate(month + "01", "yyyyMMdd");
        } catch (Exception ex) {
            return "月份格式不正确,格式应该为YYYYMM";
        }
        return null;
    }

    /**
     * 验证期初月份
     *
     * @param capitalDetail
     * @return
     */
    private String verifyBeginBalaceCapitalMonth(TblRrOtherCapitalDetail capitalDetail) {
        try {
            String leastBeginBalaceCapitalMonth = tblRrOtherCapitalDetailService.getLeastBeginBalaceCapitalMonth(capitalDetail);
            if (!StringUtils.isEmpty(leastBeginBalaceCapitalMonth)
                    && leastBeginBalaceCapitalMonth.compareTo(capitalDetail.getCapitalMonth()) > 0) {
                return "月份不能少于" + leastBeginBalaceCapitalMonth;
            }
        } catch (Exception ex) {
            log.error("系统验证异常",ex);
            return "系统验证异常";
        }
        return null;
    }

    @Override
    protected List<TblRrOtherCapitalDetail> getExportDate(Map<String, Object> params) throws ServiceException {
        List<TblRrOtherCapitalDetail> list = super.getExportDate(params);
        if(!CollectionUtils.isEmpty(list)){
            for(TblRrOtherCapitalDetail info:list){
                if(!StringUtils.isEmpty(info.getFileUrl())){
                    info.setFileUrl(fileDownloadUrl + info.getFileUrl());
                }
            }
        }
        return list;
    }


    @Override
    protected void setFootModel(Map<String, Object> result, Map<String, Object> model) throws ServiceException {
        List<TblRrOtherCapitalDetail> rows = (List<TblRrOtherCapitalDetail>) result.get("rows");
        if(!CollectionUtils.isEmpty(rows)){
            for(TblRrOtherCapitalDetail info:rows){
                if(!StringUtils.isEmpty(info.getFileUrl())){
                    info.setFileUrl(fileDownloadUrl + info.getFileUrl());
                }
            }
        }

        result.put("foot", tblRrOtherCapitalDetailService.getFoot(model));
    }

    /**
     * 导出截图
     *
     * @param request
     * @param response
     */
    @GetMapping("exportPic")
    @ApiOperation("导出截图")
    public void exportExcelPic(HttpServletRequest request, HttpServletResponse response) throws Exception {
        exportPic(request, response, this::getExportDate);
    }

    /*String getZipFileName(Map<String, Object> params){
        String ncVirtualAccount = (String) params.get("ncVirtualAccount");
        String ncShopName = (String) params.get("ncShopName");
        String capitalMonth = (String) params.get("capitalMonth");
        String zipFileName = (String) params.get("zipFileName");
        StringBuffer sb = new StringBuffer();
        sb.append(zipFileName);
        if(StringUtils.isNotBlank(capitalMonth)){
            sb.append("_"+capitalMonth);
        }
        if(StringUtils.isNotBlank(ncShopName)){
            sb.append("_"+ncShopName);
        }
        if(StringUtils.isNotBlank(ncVirtualAccount)){
            sb.append("_"+ncVirtualAccount);
        }
        return sb.toString();
    }*/

    String getPicFileName(TblRrOtherCapitalDetail detail){
        String ncShopName = detail.getNcShopName();
        String ncVirtualAccountName = detail.getNcVirtualAccountName();
        String shopName = detail.getShopName();
        String channelName = detail.getChannelName();
        String shopAccount = detail.getShopAccount();
        String capitalMonth = detail.getCapitalMonth();
        String fileUrl = detail.getFileUrl();
        String ncEnterAccountBody = detail.getNcEnterAccountBody();
        if(StringUtils.isBlank(fileUrl)){
            return null;
        }
        StringBuffer sb = new StringBuffer();
        sb.append(capitalMonth);
        if(StringUtils.isNotBlank(channelName)){
            sb.append("_"+channelName);
            if(StringUtils.isNotBlank(shopName)){
                sb.append("_"+shopName);
            }else if(StringUtils.isNotBlank(shopAccount)){
                sb.append("_"+shopAccount);
            }
            if(StringUtils.isNotBlank(ncEnterAccountBody)){
                sb.append("_"+ncEnterAccountBody);
            }
        }else if(StringUtils.isNotBlank(ncShopName)){
            TblReceiveRefundShop shop = null;
            try {
                shop = tblReceiveRefundShopService.getByNcShopName(ncShopName);
                if(shop!=null){
                    channelName = shop.getChannelName();
                }
            } catch (ServiceException e) {
                log.error(e.getMessage(),e);
            }
                sb.append("_"+channelName);
                sb.append("_"+ncShopName);
        }else{
            if(StringUtils.isNotBlank(ncVirtualAccountName)){
                try {
                    channelName = tblReceiveRefundAccountService.getChannelNameByNcVirtualAccountName(ncVirtualAccountName);
                } catch (ServiceException e) {
                    log.error(e.getMessage(),e);
                }
                sb.append("_"+channelName);
                sb.append("_"+ncVirtualAccountName);
            }
            if(StringUtils.isNotBlank(ncEnterAccountBody)){
                sb.append("_"+ncEnterAccountBody);
            }
        }
        return sb.toString()+getExtName(fileUrl);
    }

    protected Map<String, Object> buildParam(HttpServletRequest request) {
        Map<String, Object> params = new HashMap<>(16);
        for (Map.Entry<String, String[]> entry : request.getParameterMap().entrySet()) {
            String value = entry.getValue()[0];
            if (!StringUtils.isEmpty(value)) {
                value = StringEscapeUtils.unescapeHtml4(value);
                params.put(entry.getKey(), value);
            }
        }

        return params;
    }

    protected void exportPic(HttpServletRequest request, HttpServletResponse response, Function<Map<String, Object>, List<TblRrOtherCapitalDetail>> getDatas) throws IOException, ServiceException {
        Map<String, Object> params = buildParam(request);
        setParamsModel(params);
        final String zipExt = ".zip";
        // 压缩文件的文件名
        String zipFileName = (String) params.get("fileName");
        if(zipFileName.endsWith(zipExt)){
            zipFileName+=zipExt;
        }
        String path = exportRootPath + System.currentTimeMillis() + "/";

        File file = null;
        File dir = new File(path);
        if(!dir.exists()){
            dir.mkdirs();
        }

        FileInputStream in = null;
        OutputStream out = null;

        try {
            List<TblRrOtherCapitalDetail> data = getDatas.apply(params);
            file = getNetFiles(data,zipFileName,path);
            response.reset();
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/x-msdownload");
            response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());

            in = new FileInputStream(file);
            out = response.getOutputStream();
            byte[] buf = new byte[4089];
            int len;
            while ((len = in.read(buf)) > 0) {
                out.write(buf, 0, len);
            }

        } catch (Exception e) {
            log.error("导出异常", e);
            throw new ServiceException("导出异常");
        } finally {
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            file.delete();
            dir.delete();
        }
    }

    public File getNetFiles(List<TblRrOtherCapitalDetail> list,String zipFileName,String path) throws Exception {
        ZipOutputStream out = null;
        File zipfile = new File(path + zipFileName);
        try {
            out = new ZipOutputStream(new FileOutputStream(zipfile));
            byte[] buf = new byte[4096];

            List<String>picNameList = new ArrayList<>();
            for(TblRrOtherCapitalDetail detail: list){
                String fileUrl = detail.getFileUrl();
                if(fileUrl==null){
                    continue;
                }
                FileInputStream in = null;
                File file = null;
                try {
                    String picFileName = getPicFileName(detail);
                    int i = 2;
                    String tempPicFileName = picFileName;
                    while (picNameList.contains(tempPicFileName)){
                        String numStr = "(" + (i++)+")";
                        int dotIndex = picFileName.lastIndexOf(".");
                        if(dotIndex!=-1) {
                            tempPicFileName = picFileName.substring(0,dotIndex) + numStr + picFileName.substring(dotIndex);
                        }else {
                            tempPicFileName = picFileName + numStr;
                        }
                        if(i>1000){
                            throw new ServiceException("The loop may be dead, so an exception is thrown,i: "+i);
                        }
                    }
                    picFileName = tempPicFileName;
                    file = downloadNetToLocal(fileUrl,path,picFileName);
                    picNameList.add(picFileName);
                    if(file==null){
                        continue;
                    }
                    in = new FileInputStream(file);
                    out.putNextEntry(new ZipEntry(file.getName()));
                    int len;
                    while( (len = in.read(buf)) > 0){
                        out.write(buf, 0, len);
                    }
                    out.closeEntry();
                } catch (Exception e) {
                    log.info("文件压缩流导入异常",e);
                    if(out != null){
                        out.close();
                    }
                    if(zipfile != null){
                        zipfile.delete();
                    }
                    if(zipfile.getParentFile() != null){
                        zipfile.getParentFile().delete();
                    }
                    throw e;
                } finally {
                    if(in != null){
                        in.close();
                    }
                    if(file != null){
                        file.delete();
                    }
                }
            }
        } catch (IOException ex){
            log.info("文件压缩流导入异常",ex);
            throw ex;
        } finally {
            if(out != null){
                out.close();
            }
        }
        return zipfile;
    }

    String getFileName(String fileUrl){
        if(StringUtils.isBlank(fileUrl)){
            return null;
        }
        int index = fileUrl.lastIndexOf("/");
        if(index<0){
            return null;
        }
        return fileUrl.substring(index+1);
    }

    String getExtName(String fileUrl){
        if(StringUtils.isBlank(fileUrl)){
            return null;
        }
        int index = fileUrl.lastIndexOf(".");
        if(index<0){
            return null;
        }
        return fileUrl.substring(index);
    }

    private File downloadNetToLocal(String fileUrl,String path,String fileName) throws Exception {
        // 下载网络文件
        int bytesum = 0;
        int byteread = 0;
        File file = null;
        try{
            URL url = new URL(fileUrl);
            //String fileName = getFileName(fileUrl);
            if(StringUtils.isBlank(fileName)){
                return null;
            }
            file = new File(path + fileName);
            URLConnection conn = null;
            InputStream inStream = null;
            FileOutputStream fs = null;
            try {
                conn = url.openConnection();
                inStream = conn.getInputStream();
                fs = new FileOutputStream(file);

                byte[] buffer = new byte[1204];
                int length;
                while ((byteread = inStream.read(buffer)) != -1) {
                    bytesum += byteread;
                    fs.write(buffer, 0, byteread);
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                log.info("FileNotFoundException:"+fileUrl);
                return null;
            } catch (IOException e) {
                e.printStackTrace();
                log.info("IOException:"+fileUrl);
                return null;
            }finally {
                if(inStream!=null){
                    inStream.close();
                }
                if(fs!=null){
                    fs.close();
                }
            }
        } catch (IOException ex){
            log.info("文件压缩流导入异常",ex);
            throw ex;
        } finally {

        }

        return file;
    }


}

